import { invoke } from '@tauri-apps/api/core';

// 日志级别
export enum LogLevel {
  DEBUG = 0,
  INFO = 1,
  WARN = 2,
  ERROR = 3,
  FATAL = 4,
}

// 日志条目接口
export interface LogEntry {
  level: LogLevel;
  message: string;
  timestamp: number;
  component?: string;
  metadata?: Record<string, any>;
  stack?: string;
}

// 日志配置
interface LoggerConfig {
  level: LogLevel;
  enableConsole: boolean;
  enableBackend: boolean;
  enableStorage: boolean;
  maxStorageEntries: number;
  component?: string;
}

class Logger {
  private config: LoggerConfig;
  private storage: LogEntry[] = [];

  constructor(config: Partial<LoggerConfig> = {}) {
    this.config = {
      level: LogLevel.INFO,
      enableConsole: true,
      enableBackend: true,
      enableStorage: true,
      maxStorageEntries: 1000,
      ...config,
    };
  }

  // 创建日志条目
  private createLogEntry(
    level: LogLevel,
    message: string,
    metadata?: Record<string, any>,
    component?: string
  ): LogEntry {
    return {
      level,
      message,
      timestamp: Date.now(),
      component: component || this.config.component,
      metadata,
      stack: level >= LogLevel.ERROR ? new Error().stack : undefined,
    };
  }

  // 记录日志
  private async log(
    level: LogLevel,
    message: string,
    metadata?: Record<string, any>,
    component?: string
  ) {
    // 检查日志级别
    if (level < this.config.level) {
      return;
    }

    const entry = this.createLogEntry(level, message, metadata, component);

    // 控制台输出
    if (this.config.enableConsole) {
      this.logToConsole(entry);
    }

    // 存储到内存
    if (this.config.enableStorage) {
      this.logToStorage(entry);
    }

    // 发送到后端
    if (this.config.enableBackend) {
      await this.logToBackend(entry);
    }
  }

  // 控制台输出
  private logToConsole(entry: LogEntry) {
    const timestamp = new Date(entry.timestamp).toISOString();
    const component = entry.component ? `[${entry.component}]` : '';
    const message = `${timestamp} ${component} ${entry.message}`;

    switch (entry.level) {
      case LogLevel.DEBUG:
        console.debug(message, entry.metadata);
        break;
      case LogLevel.INFO:
        console.info(message, entry.metadata);
        break;
      case LogLevel.WARN:
        console.warn(message, entry.metadata);
        break;
      case LogLevel.ERROR:
      case LogLevel.FATAL:
        console.error(message, entry.metadata, entry.stack);
        break;
    }
  }

  // 存储到内存
  private logToStorage(entry: LogEntry) {
    this.storage.push(entry);

    // 限制存储条目数量
    if (this.storage.length > this.config.maxStorageEntries) {
      this.storage = this.storage.slice(-this.config.maxStorageEntries);
    }
  }

  // 发送到后端
  private async logToBackend(entry: LogEntry) {
    try {
      await invoke('add_log', {
        log: {
          level: LogLevel[entry.level].toLowerCase(),
          message: entry.message,
          component: entry.component,
          metadata: entry.metadata,
        },
      });
    } catch (error) {
      // 避免无限循环，不使用 logger 记录此错误
      console.error('Failed to log to backend:', error);
    }
  }

  // 公共日志方法
  debug(message: string, metadata?: Record<string, any>, component?: string) {
    return this.log(LogLevel.DEBUG, message, metadata, component);
  }

  info(message: string, metadata?: Record<string, any>, component?: string) {
    return this.log(LogLevel.INFO, message, metadata, component);
  }

  warn(message: string, metadata?: Record<string, any>, component?: string) {
    return this.log(LogLevel.WARN, message, metadata, component);
  }

  error(message: string, metadata?: Record<string, any>, component?: string) {
    return this.log(LogLevel.ERROR, message, metadata, component);
  }

  fatal(message: string, metadata?: Record<string, any>, component?: string) {
    return this.log(LogLevel.FATAL, message, metadata, component);
  }

  // 获取存储的日志
  getLogs(level?: LogLevel, component?: string): LogEntry[] {
    let logs = this.storage;

    if (level !== undefined) {
      logs = logs.filter(entry => entry.level >= level);
    }

    if (component) {
      logs = logs.filter(entry => entry.component === component);
    }

    return logs.sort((a, b) => b.timestamp - a.timestamp);
  }

  // 清除存储的日志
  clearLogs() {
    this.storage = [];
  }

  // 更新配置
  updateConfig(config: Partial<LoggerConfig>) {
    this.config = { ...this.config, ...config };
  }

  // 创建子 logger
  createChild(component: string): Logger {
    return new Logger({
      ...this.config,
      component,
    });
  }

  // 性能测量
  time(label: string, component?: string) {
    const startTime = performance.now();

    return {
      end: () => {
        const duration = performance.now() - startTime;
        this.info(
          `Timer [${label}]: ${duration.toFixed(2)}ms`,
          { duration },
          component
        );
        return duration;
      },
    };
  }

  // 异步操作包装
  async withLogging<T>(
    operation: () => Promise<T>,
    operationName: string,
    component?: string
  ): Promise<T> {
    const timer = this.time(operationName, component);

    try {
      this.debug(`Starting operation: ${operationName}`, undefined, component);
      const result = await operation();
      timer.end();
      this.debug(`Operation completed: ${operationName}`, undefined, component);
      return result;
    } catch (error) {
      timer.end();
      this.error(
        `Operation failed: ${operationName}`,
        { error: error instanceof Error ? error.message : String(error) },
        component
      );
      throw error;
    }
  }

  // 批量日志
  batch(
    entries: Array<{
      level: LogLevel;
      message: string;
      metadata?: Record<string, any>;
      component?: string;
    }>
  ) {
    return Promise.all(
      entries.map(entry =>
        this.log(entry.level, entry.message, entry.metadata, entry.component)
      )
    );
  }
}

// 创建全局 logger 实例
export const logger = new Logger();

// 便捷函数
export const debug = (
  message: string,
  metadata?: Record<string, any>,
  component?: string
) => {
  return logger.debug(message, metadata, component);
};

export const info = (
  message: string,
  metadata?: Record<string, any>,
  component?: string
) => {
  return logger.info(message, metadata, component);
};

export const warn = (
  message: string,
  metadata?: Record<string, any>,
  component?: string
) => {
  return logger.warn(message, metadata, component);
};

export const error = (
  message: string,
  metadata?: Record<string, any>,
  component?: string
) => {
  return logger.error(message, metadata, component);
};

export const fatal = (
  message: string,
  metadata?: Record<string, any>,
  component?: string
) => {
  return logger.fatal(message, metadata, component);
};

// React Hook
export const useLogger = (component?: string) => {
  const componentLogger = component ? logger.createChild(component) : logger;

  return {
    debug: (message: string, metadata?: Record<string, any>) =>
      componentLogger.debug(message, metadata),
    info: (message: string, metadata?: Record<string, any>) =>
      componentLogger.info(message, metadata),
    warn: (message: string, metadata?: Record<string, any>) =>
      componentLogger.warn(message, metadata),
    error: (message: string, metadata?: Record<string, any>) =>
      componentLogger.error(message, metadata),
    fatal: (message: string, metadata?: Record<string, any>) =>
      componentLogger.fatal(message, metadata),
    time: (label: string) => componentLogger.time(label, component),
    withLogging: <T>(operation: () => Promise<T>, operationName: string) =>
      componentLogger.withLogging(operation, operationName, component),
  };
};

// 性能监控
export const performanceLogger = {
  measureRender: (componentName: string) => {
    return logger.time(`Render: ${componentName}`, 'performance');
  },

  measureAsync: async <T>(
    operation: () => Promise<T>,
    operationName: string
  ): Promise<T> => {
    return logger.withLogging(operation, operationName, 'performance');
  },

  measureSync: <T>(operation: () => T, operationName: string): T => {
    const timer = logger.time(operationName, 'performance');
    try {
      const result = operation();
      timer.end();
      return result;
    } catch (error) {
      timer.end();
      logger.error(
        `Sync operation failed: ${operationName}`,
        { error: error instanceof Error ? error.message : String(error) },
        'performance'
      );
      throw error;
    }
  },
};

export default logger;
